package org.ejc.api.registration;

import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.naming.NamingException;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Category;
import org.apache.log4j.NDC;
import org.ejc.datatype.registrant.RegistrantSearchCriteria;
import org.ejc.exception.EJCPersistenceException;
import org.ejc.persist.model.Convention;
import org.ejc.persist.model.ConventionActivityHistory;
import org.ejc.persist.model.ConventionRegistrant;
import org.ejc.persist.model.CountryCode;
import org.ejc.persist.model.LanguageIso;
import org.ejc.persist.model.Registrant;
import org.ejc.persist.model.RegistrantStatusType;
import org.ejc.util.EJCUtils;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Expression;


/**
 * @author zac
 * 
 * @ejb.bean type="Stateless" name="RegistrationAPI"
 *           description="RegistrationAPI session bean"
 *           local-jndi-name="org.ejc/RegistrationAPILocalHome"
 *           jndi-name="org.ejc/RegistrationAPIHome" view-type="both"
 * 
 * @ejb.ejb-ref ejb-name="RegistrationAPI" ref-name="ejb/RegistrationAPI"
 *              view-type="both"
 * 
 * @ejb.transaction type="RequiresNew"
 * @ejb.util generate = "physical"
 */
public abstract class RegistrationAPIBean implements SessionBean {

	Category log = Category.getInstance(RegistrationAPIBean.class);

	/**
	 * Create A Registration.<p/>
	 * This method will insert an entry into the Registrant table and the ConventionRegistrant table.<p/>
	 * 
	 * 
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public ConventionRegistrant createFullRegistrant(Registrant registrant,
			ConventionRegistrant convRegistrant) throws NamingException,
			EJBException {
		Session hsession = null;
		Transaction tx = null;
		try {
			if(!isConventionActive()){
				return null;
			}
			
			
			hsession = EJCUtils.getHibernateSession();
			Convention conv=(Convention)hsession.load(Convention.class,new Integer(1));
			CountryCode countryCode=(CountryCode)hsession.load(CountryCode.class,registrant.getAddress().getCountryCode().getCountryId());
			
			tx = hsession.beginTransaction();

			if (log.isDebugEnabled()) {
				log.debug("About to create a registrant now ....");
			}
			Integer registrantId = (Integer) hsession.save(registrant);
			if (log.isDebugEnabled()) {
				log.debug("Registrant  created and its ID is [" + registrantId
						+ "]");
			}
			registrant.setRegistrantId(registrantId);
			
			// set the registrantId within the conventionRegistrant object
			convRegistrant.setRegistrantId(registrantId);

			if(!Boolean.valueOf(convRegistrant.getPreReg())){
				RegistrantStatusType regStatus = new RegistrantStatusType();
				regStatus.setId(1);
				convRegistrant.setRegistrantStatusType(regStatus);
			}else if(Boolean.valueOf(convRegistrant.getPreReg())){
				RegistrantStatusType regStatus = new RegistrantStatusType();
				regStatus.setId(2);
				convRegistrant.setRegistrantStatusType(regStatus);
			}
			
			if (convRegistrant != null
					&& Boolean.valueOf(convRegistrant.getPreReg())) {
				// ok gotta create a preRegCode now.
				
				NumberFormat format=new DecimalFormat("00000");
				StringBuffer buf=new StringBuffer();
				buf.append(conv.getConventionName());
				buf.append("-"+format.format(registrantId));
				buf.append("-"+registrant.getFirstName()+registrant.getLastName());
				buf.append("-"+countryCode.getCountryIsoCode());

				// now set the code
				convRegistrant.setPreReg(buf.toString());
			} else {
				// ensure that its definately null so as to avoid confusion.
				convRegistrant.setPreReg(null);
			}
			

			// if the language is null, set to a default of 1.
			if (convRegistrant.getLanguageIso() == null) {
				LanguageIso isoLang = new LanguageIso();
				isoLang.setLanguageId(1);
				convRegistrant.setLanguageIso(isoLang);
			}
			convRegistrant.setRegistrationDate(new Date());
			hsession.save(convRegistrant);
			Hibernate.initialize(convRegistrant.getAccomodationType());
			tx.commit();
			hsession.flush();
			
			return convRegistrant;
		} catch (EJCPersistenceException ej) {
			log.fatal("Error in getting handle on persister!", ej);
			if(tx!=null)tx.rollback();
		} catch (HibernateException he) {
			log.fatal("Hibernate Exception.", he);
			if(tx!=null)tx.rollback();
		} catch (Exception e) {
			log.fatal("General Exception", e);
			if(tx!=null)tx.rollback();
		} finally {
			if (hsession != null) {
				try {
					hsession.close();
				} catch (Exception e) {
					log.warn("Failed to close off hibernate session!");
				}
			}
		}
		return convRegistrant;
	}
	
	/**
	 * Update a conventionRegistrant
	 * @param conventionReg
	 * @return The updated ConventionRegistrant object
	 * @ejb.interface-method view-type="both"
	 */
	public ConventionRegistrant updateRegistrant(ConventionRegistrant conventionReg)
	{
		Session hsession = null;
		Transaction tx = null;
		try {
			NDC.push("[UpdateRegistrant]");
			NDC.push("["+conventionReg.getRegistrantId()+"]");
			hsession = EJCUtils.getHibernateSession();
			tx = hsession.beginTransaction();
			Registrant registrant = conventionReg.getRegistrant();
			//AccomodationType accomType = conventionReg.getAccomodationType();
			hsession.update(registrant);
			//hsession.update(accomType);
			hsession.update(conventionReg);
			tx.commit();
			hsession.flush();
		} catch (EJCPersistenceException e) {
			log.fatal("Error when updating the Registrant");
			e.printStackTrace();
		}finally{
			NDC.pop();
		}
		return conventionReg;
	}
	
	/**
	 * Select a Registrant by it ID
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public ConventionRegistrant selectRegistrantById(Integer registrantId){
		Session hsession = null;
		ConventionRegistrant conventionReg = null;
		try {
			hsession = EJCUtils.getHibernateSession();
			log.debug("Searching for conventionregistrant with ID ["+registrantId+"]");
			conventionReg = (ConventionRegistrant) hsession.createCriteria(ConventionRegistrant.class)
				.add(Expression.eq("registrantId", registrantId))
				.uniqueResult();
			log.debug("Found conventionRegistrant for Id ["+registrantId+"]");
		} catch (EJCPersistenceException e) {
			log.fatal("Error getting Hibernate Session instance when selecting a Registrant by Id");
			e.printStackTrace();
		}
		return conventionReg;
	}

	/**
	 * Select the number of guests. CAn be onsite or pending Arrival guests guests
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public Integer selectNumOfGuests(Integer guestFilter){
		Session hsession = null;
		Integer numGuests = null;
		try {
			hsession = EJCUtils.getHibernateSession();
			numGuests = (Integer)hsession.createQuery("select count(*) from ConventionRegistrant cr where " +
					"cr.registrantStatusType.id = :filter ").setInteger("filter", guestFilter).uniqueResult();
		} catch (EJCPersistenceException e) {
			log.fatal("Error getting Hibernate Session instance when selecting a Registrant by Id");
			e.printStackTrace();
		}
		return numGuests;
	}

	
	/**
	 * Select a Registrant by it ID
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public boolean isConventionActive(){
		Session hsession=null;
		try {
			hsession = EJCUtils.getHibernateSession();
			Convention convention=(Convention)hsession.load(Convention.class,new Integer(1));
			if(convention.getConventionStatus().equalsIgnoreCase("INACTIVE")){
				return false;
			}
		}catch(Exception e){
			log.fatal(e);
		}finally{
			hsession.close();
		}
		return true;
	}
	
	/**
	 * Select a Registrant by it ID
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public void pauseRegistration(){
		Session hsession=null;
		Transaction tx=null;
		try {
			hsession = EJCUtils.getHibernateSession();
			Convention convention=(Convention)hsession.load(Convention.class,new Integer(1));
			convention.setConventionStatus("INACTIVE");
			convention.setConventionStatusLastInActive(new Date());
			tx=hsession.beginTransaction();
			hsession.saveOrUpdate(convention);
			tx.commit();
			hsession.flush();
			log.fatal("Convention is now inactive!");
		} catch (EJCPersistenceException e) {
			log.fatal(e);
		}finally{
			hsession.close();
		}
	}
	
	/**
	 * Select a Registrant by it ID
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public Date getLastActiveDate(){
		Session hsession=null;
		Date returnDate=null;
		try {
			hsession = EJCUtils.getHibernateSession();
			Convention convention=(Convention)hsession.load(Convention.class,new Integer(1));
			if(convention.getConventionStatusLastActive()==null){
				return convention.getConventionStartdate();
			}
			returnDate =new Date(convention.getConventionStatusLastActive().getTime());
		} catch (EJCPersistenceException e) {
			log.fatal(e);
		}finally{
			hsession.close();
		}
		return returnDate;
	}
	
	/**
	 * Select a Registrant by it ID
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public Date getLastInActiveDate(){
		Session hsession=null;
		Date returnDate=null;
		try {
			hsession = EJCUtils.getHibernateSession();
			Convention convention=(Convention)hsession.load(Convention.class,new Integer(1));
			if(convention.getConventionStatusLastInActive()==null){
				return null;
			}
			returnDate =new Date(convention.getConventionStatusLastInActive().getTime());
		} catch (EJCPersistenceException e) {
			log.fatal(e);
		}finally{
			hsession.close();
		}
		return returnDate;
	}
	
	
	/**
	 * Select a Registrant by it ID
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public void activateRegistration(){
		Session hsession=null;
		Transaction tx=null;
		Date oldStartDate=null;
		Date now=null;
		try {
			hsession = EJCUtils.getHibernateSession();
			Convention convention=(Convention)hsession.load(Convention.class,new Integer(1));
			convention.setConventionStatus("ACTIVE");
			now=new Date();
			oldStartDate=convention.getConventionStatusLastActive();
			
			convention.setConventionStatusLastActive(now);
			tx=hsession.beginTransaction();
			hsession.save(convention);
			
			ConventionActivityHistory historyObj=new ConventionActivityHistory();
			historyObj.setConventionId(new Integer(1));
			historyObj.setStartTime(new Timestamp(oldStartDate.getTime()));
			historyObj.setEndTime(new Timestamp(now.getTime()));
			hsession.save(historyObj);
			
			tx.commit();
			hsession.flush();
			log.fatal("Convention is now ACTIVE!");
			tx=null;
		} catch (EJCPersistenceException e) {
			log.fatal(e);
			tx.rollback();
		}finally{
			hsession.close();
		}
	}
	
	
	
	/**
	 * Create A Registration.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public void test() throws NamingException, EJBException {
		log.fatal("TEST TEST");
		PreRegUpload u=new PreRegUpload();
		u.beginProcess();
		
		
	}

	/**
	 * Search for a Registrant.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public List searchRegistrants(RegistrantSearchCriteria searchCriteria, int resultIndex, int resultSize) throws NamingException, EJBException {
		Session hsession = null;
		List<ConventionRegistrant> returnList=new ArrayList<ConventionRegistrant>();
		
		try {
			hsession = EJCUtils.getHibernateSession();

			List regs = null;
			Criteria crit = hsession.createCriteria(ConventionRegistrant.class);
			if(searchCriteria.isAdvancedSearch()){
				if(searchCriteria.getFirstName().length() != 0 || searchCriteria.getAdvLastName().length() != 0 || searchCriteria.getCountryId() != 0
						|| StringUtils.isNotEmpty(searchCriteria.getNotes())){
					Criteria regCrit = crit.createCriteria("registrant");
					if(searchCriteria.getFirstName().length() != 0){
						regCrit.add(Expression.like("firstName", "%"+searchCriteria.getFirstName()+"%"));
					}
					if(searchCriteria.getAdvLastName().length() != 0){
						regCrit.add(Expression.like("lastName", "%"+searchCriteria.getAdvLastName()+"%"));
					}
					if(StringUtils.isNotEmpty(searchCriteria.getNotes())){
						regCrit.add(Expression.like("notes", "%"+searchCriteria.getNotes()+"%"));
					}
					if(searchCriteria.getCountryId() != 0){
						Criteria addressCrit = regCrit.createCriteria("address");
						addressCrit.createCriteria("countryCode").add(Expression.eq("countryId", searchCriteria.getCountryId()));
					}
					
				}
				if(searchCriteria.getAccommodationTypeId() != 0){
					crit.createCriteria("accomodationType")
						.add(Expression.eq("accomodationTypeId", searchCriteria.getAccommodationTypeId()));
				}
				if(searchCriteria.getLengthOfStay() != 0){
					crit.add(Expression.eq("lengthOfStay", searchCriteria.getLengthOfStay()));
				}
				if(searchCriteria.getAdvPreRegCode().length() != 0){
					crit.add(Expression.eq("preReg", searchCriteria.getAdvPreRegCode()));
				}
				if(searchCriteria.getPreRegistration()){
					crit.add(Expression.isNotNull("preReg"));
				}
				if(searchCriteria.getRegTypeId() != 0){
					crit.createCriteria("registrantType").add(Expression.eq("registrantTypeId", searchCriteria.getRegTypeId()));
				}
				
				if(searchCriteria.getStatusId()!=0){
					crit.createCriteria("registrantStatusType").add(Expression.eq("id",searchCriteria.getStatusId()));
				}
				
				
				
				
			}else{
				if(searchCriteria.getLastName().length() != 0){
					Criteria regCrit = crit.createCriteria("registrant");
					regCrit.add(Expression.like("lastName", "%"+searchCriteria.getLastName()+"%"));
				}
				if(searchCriteria.getPreRegCode().length() != 0){
					crit.add(Expression.eq("preReg", searchCriteria.getPreRegCode()));
				}
			}
				
				if(resultSize != 0){
					regs = crit.setFirstResult(resultIndex).setMaxResults(resultSize).list();
				}else{
					regs = crit.list();
				}
				
			return regs;			
		} catch (EJCPersistenceException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			log.fatal("Error in getting list of registrants");
		}
		hsession.close();
		return null;

	}
	
	/**
	 * Get a list of all the registrant status types.
	 * @return
	 * @throws NamingException
	 * @throws EJBException
	 * @ejb.interface-method view-type="both"
	 */
	public Collection getRegistrantStatusTypes() throws NamingException, EJBException {
		Session hsession = null;
		try {
			hsession = EJCUtils.getHibernateSession();
			Criteria crit = hsession.createCriteria(RegistrantStatusType.class);
			return crit.list();
		} catch (EJCPersistenceException epe) {
			epe.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (hsession != null) {
				hsession.close();
			}
		}
		return null;
	}
	
}